import os
import asyncio
import time
import uuid
import bcrypt
from pydantic import ValidationError


if __name__ == "__main__":
    os.chdir('..')
    from src.main import db, logger
    from src.models import *
    from src.exceptions import *
    import src.config as config

    async def get_all_users_test() -> str:
        res = await db.get_users()
        if isinstance(res, list):
            return "PASS"
        else:
            return f"FAIL. all users return must be list but {type(res)} was returned"

    async def get_user_test(user_id: uuid.UUID) -> str:
        res = await db.get_user(user_id)
        if isinstance(res, User):
            return "PASS"
        else:
            return f"FAIL. user return must be model.User but {type(res)} was returned"

    async def del_user_test(user_id: uuid.UUID) -> str:
        await db.del_user(user_id)
        try:
            user = await db.get_user(user_id)
            return "FAIL. User found in database."
        except UserNotFound:
            return "PASS"

    async def create_user_test() -> (User, str):
        new_user = User(**{"user_id": uuid.uuid4(),
                           "username": "TEST",
                           "password": bcrypt.hashpw("test123".encode(), bcrypt.gensalt()),
                           "created_at": time.time(),
                           "updated_at": None})
        if not bcrypt.checkpw("test123".encode(), new_user.password):
            raise InvalidPassword("error while checking passwords hash")
        res = await db.add_user(new_user)
        if res is None:
            return new_user, "PASS"
        else:
            return new_user, f"FAIL. res is not None."

    async def update_user_test(user: User) -> str:
        try:
            user.id = uuid.uuid4()
            return 'FAIL. uuid must be frozen'
        except ValidationError:
            pass
        try:
            user.created_at = time.time()
            return 'FAIL. created_at must be frozen'
        except ValidationError:
            pass
        user.username = "NEW TEST"
        user.password = bcrypt.hashpw("new_test123".encode(), bcrypt.gensalt())
        if not bcrypt.checkpw("new_test123".encode(), user.password):
            raise InvalidPassword("error while checking passwords hash")
        await db.update_user(user)
        updated_user = await db.get_user(user.id)
        logger.debug(updated_user)
        if updated_user != user:
            return 'FAIL. user not changed'
        return 'PASS'

    async def tests():
        logger.debug("Test 1. Getting all users")
        logger.debug(await get_all_users_test())

        logger.debug("Test 2. Creating user")
        created_user, msg = await create_user_test()
        logger.debug(created_user)
        logger.debug(msg)

        logger.debug("Test 3. Selecting created user")
        logger.debug(await get_user_test(created_user.id))

        logger.debug("Test 4. Updating created user")
        logger.debug(await update_user_test(created_user))

        logger.debug("Test 5. Deleting created user")
        logger.debug(await del_user_test(created_user.id))


    asyncio.run(tests())
